package com.example.mytestdemo.linearlayoutmanager.dragon

import android.graphics.Path
import android.graphics.PathMeasure
import android.graphics.PointF
import android.util.Log
import androidx.annotation.FloatRange


/**
 * @author tgw
 * @date 2022/8/29
 * @describe
 */


/**
 *存储 路径上的 所有点坐标
 */
class Keyframes {

    companion object {
        private const val TAG = "Keyframes"
        private const val PRECISION = 0.1f
    }

    var mX //Path的所有x轴坐标点
            : FloatArray? = null
    var mY //Path的所有y轴坐标点
            : FloatArray? = null
    var mAngle //Path上每一个坐标所对应的角度
            : FloatArray? = null

    var pathLength: Float = 0f
    var numPoints: Int = 0

    //辅助测量整体的recycleview宽高
    var mMaxX = 0f
    var mMaxY = 0f

    constructor(path: Path) {
        initPath(path)
    }


    private fun initPath(path: Path) {
        val pathMeasure = PathMeasure(path, false)
        pathLength = pathMeasure.length
        numPoints = ((pathLength / PRECISION) + 1).toInt()
        Log.d(TAG, "initPath 建立长度:$pathLength ---numPoints:$numPoints")

        mX = FloatArray(numPoints)
        mY = FloatArray(numPoints)
        mAngle = FloatArray(numPoints)

        //临时存放坐标点
        val position = FloatArray(2)
        //临时存放正切值
        val tangent = FloatArray(2)
        //当前距离
        var distance: Float
        for (i in 0 until numPoints) {
            //更新当前距离
            distance = i * pathLength / (numPoints - 1)
            //根据当前距离获取对应的坐标点和正切值
            pathMeasure.getPosTan(distance, position, tangent)
            if (position[0] > mMaxX) {
                mMaxX = position[0]
            }
            if (position[1] > mMaxY) {
                mMaxY = position[1]
            }
            mX?.set(i, position[0])
            mY?.set(i, position[1])
            //利用反正切函数得到角度 // https://www.cnblogs.com/yimeixiaobai1314/p/15698676.html
            // http://www.qiutianaimeili.com/html/page/2021/02/20314txw5nhe1uq.html
            //https://www.jianshu.com/p/04f3660b1f3a
            // 2Π = 360°，rad = deg x π / 180 （rad 是弧度， deg 是角度）
            // Math.tan(45*Math.PI/180)=0.99999999 tan45° = 1，
            // Math.atan(1)=45*Math.PI/180，
            //9.462322 170.53767
            mAngle?.set(
                i, fixAngle(
                    (Math.atan2(
                        tangent[1].toDouble(),
                        tangent[0].toDouble()
                    ) * 180f / Math.PI).toFloat()
                )
            )
        }

        Log.d(TAG, "initPath 建立角度: ")
        for (i in 0 until numPoints) {
            Log.d(
                TAG,
                "initPath 建立角度1 mx: ${mX?.get(i)}---my: ${mY?.get(i)}----mAnglex: ${mAngle?.get(i)}"
            )
        }

    }

    /**
     * 调整角度，使其在0 ~ 360之间
     *
     * @param rotation 当前角度
     * @return 调整后的角度
     *
     * 传递的角度是线条的角度，要垂直于线条偏移90°
     */
    private fun fixAngle(rotation: Float): Float {
        var rotation = rotation-90
        val angle = 360f
        if (rotation < 0) {
            rotation += angle
        }
        if (rotation > angle) {
            rotation %= angle
        }
        return rotation
    }


    /**
     * 根据传入的百分比来获取对应的坐标点和角度
     * @param fraction 当前百分比: 0~1
     */
    fun getValue(@FloatRange(from = 0.0, to = 1.0) fraction: Float): PosTan? {
        //超出范围的直接返回空
        return if (fraction >= 1f || fraction < 0) {
            null
        } else {
            val index = (numPoints * fraction).toInt()
            //更新temp的内部值,mTemp就是刚刚扩展自PointF的类，用来存放这些坐标点和角度等数据。
            return PosTan().apply {
                set(mX?.get(index), mY?.get(index), mAngle?.get(index))
            }
        }
    }
}

/**
 *点坐标
 */
class PosTan : PointF {
    /**
     * 在路径上的位置 (百分比)
     */
    var fraction = 0f

    /**
     * Item所对应的索引
     */
    var index = 0

    var posTa: PosTan? = null


    /**
     * Item的旋转角度
     */
    var angle = 0f

    constructor(posTa: PosTan?, index: Int, fraction: Float) {
        this.fraction = fraction
        this.index = index
        this.posTa = posTa
    }

    constructor() : super()

    fun set(x: Float?, y: Float?, angle: Float?) {
        if (y != null && x != null) {
            set(x, y)
        }
        if (angle != null) {
            this.angle = angle
        }
    }
}
